﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Heritage.Logging;
using Heritage.Models;
using Heritage.Codebox;

namespace Heritage.Controllers
{
    public class GameMasterController : Controller
    {

        [AuthorizedValidated]
        [GameMaster]
        public ActionResult Cities()
        {
            CitiesModel model = new CitiesModel();
            HeritageEntities ents = new HeritageEntities();
            foreach (GameDescriptions gd in ents.GameDescriptions)
            {
                CityModel cm = new CityModel();
                cm.GameConditions = Utils.GetGameConditions(gd)+"<br>Количество игроков: "+((gd.MaxPlayers == gd.MinPlayers)? ""+gd.MinPlayers : gd.MinPlayers+" - "+gd.MaxPlayers);
                cm.GameName = gd.GameName;
                cm.Schedule = GameSchedule.FromGameString(gd.GameSchedule);
                cm.RatingForEnter = gd.RatingForEnter;
                cm.GameDescription = gd.GameDescription;
                switch (gd.StartCondition)
                {
                    case Constants.START_CONDITION_ONE_ALWAYS:
                        cm.StartConditionDescription = "Одна всегда на записи";
                        break;
                    case Constants.START_CONDITION_ONE_IF_NONE:
                        cm.StartConditionDescription = "Открывается на запись, когда закончится предыдущая";
                        break;
                    case Constants.START_CONDITION_ONE_RANDOM:
                        cm.StartConditionDescription = "Открывается на запись случайная из нескольких";
                        break;
                    case Constants.START_CONDITION_MANUAL:
                        cm.StartConditionDescription = "Запускается вручную";
                        break;
                    default:
                        break;

                }
                model.Cities.Add(cm);
            }
            ViewData.Model = model;
            return View();
        }
        [AuthorizedValidated]
        [GameMaster]
        public ActionResult EditCity(string id)
        {
            CityModel model = new CityModel();
            HeritageEntities ents = new HeritageEntities();
            GameDescriptions gd = ents.GameDescriptions.Where(r => r.GameName == id).FirstOrDefault();
            if (string.IsNullOrEmpty(id) || gd == null)
            {
                model.ModeCreate = true;
                model.Advocat = 0;
                model.GameDescription = "";
                model.GameName = "";
                if (id != null) model.GameName = id;
                model.Schedule = GameSchedule.FromGameString("8,2880,false,1440,8,20,BCDEF,");
                model.Girl = 0;
                model.Komissar = 1;
                model.Mafia = 2;
                model.Maniac = 0;
                model.MaxPlayers = 15;
                model.MinPlayers = 9;
                model.Private = 0;
                model.PublicVote = 0;
                model.RatingForEnter = 2.0;
                model.Reanimator = 0;
                model.Sheriff = 0;
                model.StartCondition = Constants.START_CONDITION_MANUAL;
                model.Thief = 0;
            }
            else
            {
                model.ModeCreate = false;
                model.Advocat = gd.Advocat;
                model.GameDescription = gd.GameDescription;
                model.GameName = gd.GameName;
                model.Schedule = GameSchedule.FromGameString(gd.GameSchedule);
                model.Girl = gd.Girl;
                model.Komissar = gd.Komissar;
                model.Mafia = gd.Mafia;
                model.Maniac = gd.Maniac;
                model.MaxPlayers = gd.MaxPlayers;
                model.MinPlayers = gd.MinPlayers;
                model.Private = gd.Private;
                model.PublicVote = gd.PublicVote;
                model.RatingForEnter = gd.RatingForEnter;
                model.Reanimator = gd.Reanimator;
                model.Sheriff = gd.Sheriff;
                model.StartCondition = gd.StartCondition;
                model.Thief = gd.Thief;
            }
            ViewData.Model = model;
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [AuthorizedValidated]
        [GameMaster]
        public ActionResult EditCity(FormCollection coll)
        {
            CityModel model = new CityModel();
            model.ModeCreate = string.IsNullOrEmpty(coll["city"]);
            model.Advocat = int.Parse(coll["advocat"]);
            model.GameDescription = coll["description"];
            if (model.ModeCreate) model.GameName = coll["newcity"].Trim();
            else model.GameName = coll["city"].Trim();
            model.Girl = int.Parse(coll["girl"]);
            model.Komissar = int.Parse(coll["komissar"]);
            model.Mafia = int.Parse(coll["mafia"]);
            model.Maniac = int.Parse(coll["maniac"]);
            int max = -1;
            double mmax = 0;
            model.MaxPlayers = int.TryParse(coll["maxplayers"], out max) ? max : 0;
            model.MinPlayers = int.TryParse(coll["minplayers"], out max) ? max : 0;
            model.Private = int.Parse(coll["private"]);
            model.PublicVote = int.Parse(coll["publicvote"]);
            model.RatingForEnter = double.TryParse(coll["ratingforenter"], out mmax) ? mmax : 0;
            model.Reanimator = int.Parse(coll["reanimator"]);
            model.Sheriff = int.Parse(coll["sheriff"]);
            model.StartCondition = int.Parse(coll["startcondition"]); ;
            model.Thief = int.Parse(coll["thief"]);

            HeritageEntities ents = new HeritageEntities();

            if (model.ModeCreate && ents.GameDescriptions.Where(r => r.GameName == model.GameName).FirstOrDefault() != null)
            {
                ModelState.AddModelError("err", "Город с таким именем уже существует - выберите другой");
            }
            if (!model.ModeCreate && ents.GameDescriptions.Where(r => r.GameName == model.GameName).FirstOrDefault() == null)
            {
                ModelState.AddModelError("err", "Города с таким именем нет - редактирование невозможно!");
            }
            if (model.GameName.Length < 2 || model.GameName.Length > 30 || !Utils.CheckLettersOnly(model.GameName))
            {
                ModelState.AddModelError("err", "Имя города должно быть в длину от 2 до 30 символов и содержать только буквы, минус и знак подчеркивания");
            }
            if (model.GameDescription.Length == 0)
            {
                ModelState.AddModelError("err", "Описание города не должно быть пустым");
            }
            if (model.MinPlayers < 2 || model.MaxPlayers > 25 || model.MaxPlayers < model.MinPlayers)
            {
                ModelState.AddModelError("err", "Партия должна содержать от 2 до 25 игроков, минимальное значение должно быть меньше максимального");
            }
            string sched = "";
            sched += (coll["gamestarttime"] + ",");
            int hrs = 0;
            int mins = 0;
            bool error = false;
            int full = 2880;
            if (!int.TryParse(coll["firstday"], out hrs))
            {
                try
                {
                    string[] all = coll["firstday"].Split(new[] { ":" }, StringSplitOptions.None);
                    hrs = int.Parse(all[0]);
                    mins = int.Parse(all[1]);
                }
                catch
                {
                    ViewData["FirstDayLength"] = coll["firstday"];
                    error = true;
                    ModelState.AddModelError("err", "Длительность нулевого дня должна быть в формате чч:мм или просто чч");
                }
            }
            if (!error)
            {
                if (mins < 0 || mins > 59)
                {
                    ViewData["FirstDayLength"] = coll["firstday"];
                    ModelState.AddModelError("err", "Количество минут должно быть от 0 до 59");                    
                }
                full = hrs*60 + mins;
                if (full <= 0)
                {
                    ViewData["FirstDayLength"] = coll["firstday"];
                    ModelState.AddModelError("err", "Длительность нулевого дня должна быть больше нуля");                                        
                }
                if (full > 4320)
                {
                    ViewData["FirstDayLength"] = coll["firstday"];
                    ModelState.AddModelError("err", "Длительность нулевого дня должна быть меньше или равна 72 часам");
                }
            }
            sched += (full + ",");
            if (coll["snapturn"] != null) sched += "true,";
            else sched += "false,";

            hrs = 0;
            mins = 0;
            error = false;
            full = 2880;
            if (!int.TryParse(coll["turnstep"], out hrs))
            {
                try
                {
                    string[] all = coll["turnstep"].Split(new[] { ":" }, StringSplitOptions.None);
                    hrs = int.Parse(all[0]);
                    mins = int.Parse(all[1]);
                }
                catch
                {
                    ViewData["TurnLength"] = coll["turnstep"];
                    error = true;
                    ModelState.AddModelError("err", "Длительность хода должна быть в формате чч:мм или просто чч");
                }
            }
            if (!error)
            {
                if (mins < 0 || mins > 59)
                {
                    ViewData["TurnLength"] = coll["turnstep"];
                    ModelState.AddModelError("err", "Количество минут должно быть от 0 до 59");
                }
                full = hrs * 60 + mins;
                if (full <= 0)
                {
                    ViewData["TurnLength"] = coll["turnstep"];
                    ModelState.AddModelError("err", "Длительность хода должна быть больше нуля");
                }
                if (full > 4320)
                {
                    ViewData["TurnLength"] = coll["turnstep"];
                    ModelState.AddModelError("err", "Длительность хода должна быть меньше или равна 72 часам");
                }
            }
            sched += (full + ",");

            int start = int.Parse(coll["startinterval"]);
            int end = int.Parse(coll["endinterval"]);
            if (start > end)
            {
                ModelState.AddModelError("err", "Время начала игрового интервала должно быть раньше времени его конца");                
            }
            sched += (start + "," + end +",");
            string ds = "";
            if (coll["ch_1"] != null) ds += "A";
            if (coll["ch_2"] != null) ds += "B";
            if (coll["ch_3"] != null) ds += "C";
            if (coll["ch_4"] != null) ds += "D";
            if (coll["ch_5"] != null) ds += "E";
            if (coll["ch_6"] != null) ds += "F";
            if (coll["ch_7"] != null) ds += "G";
            if (ds.Length == 0)
            {
                ModelState.AddModelError("err", "Должен быть выбран хотя бы один игровой день");
            }
            sched = sched + ds + ",";
            model.Schedule = GameSchedule.FromGameString(sched);
            if (!ModelState.IsValid)
            {
                ViewData.Model = model;
                return View();
            }
            else
            {
                if (model.ModeCreate)
                {
                    GameDescriptions desc = GameDescriptions.CreateGameDescriptions(model.GameName, Utils.GetNextValidGameNumber(model.GameName), model.StartCondition, model.MinPlayers, model.MaxPlayers, model.Mafia, model.Komissar, model.Sheriff, model.Reanimator, model.Maniac, model.Girl, model.Thief, model.Private, model.PublicVote, model.Advocat, model.RatingForEnter);
                    desc.GameDescription = model.GameDescription;
                    desc.GameSchedule = model.Schedule.ToGameString();
                    ents.GameDescriptions.AddObject(desc);
                    ents.SaveChanges();
                }
                else
                {
                    GameDescriptions desc = ents.GameDescriptions.Where(r => r.GameName == model.GameName).FirstOrDefault();
                    desc.Advocat = model.Advocat;
                    desc.GameDescription = model.GameDescription;
                    desc.GameSchedule = model.Schedule.ToGameString();
                    desc.Girl = model.Girl;
                    desc.Komissar = model.Komissar;
                    desc.Mafia = model.Mafia;
                    desc.Maniac = model.Maniac;
                    desc.MaxPlayers = model.MaxPlayers;
                    desc.MinPlayers = model.MinPlayers;
                    desc.Private = model.Private;
                    desc.PublicVote = model.PublicVote;
                    desc.RatingForEnter = model.RatingForEnter;
                    desc.Reanimator = model.Reanimator;
                    desc.Sheriff = model.Sheriff;
                    desc.StartCondition = model.StartCondition;
                    desc.Thief = model.Thief;
                    ents.SaveChanges();
                }
                return new RedirectResult("/GameMaster/Cities");
            }
        }

        [AuthorizedValidated]
        [ModeratorOrOwner]
        public ActionResult EditGame(string id)
        {
            CityModel model = new CityModel();
            HeritageEntities ents = new HeritageEntities();
            Games gd = ents.Games.Where(r => r.GameName == id).FirstOrDefault();
            if (string.IsNullOrEmpty(id) || gd == null)
            {
                model.ModeCreate = true;
                model.Advocat = 0;
                model.GameDescription = "";
                model.GameName = "";
                model.Schedule = GameSchedule.FromGameString("8,2880,false,1440,8,20,BCDEF,");
                model.Girl = 0;
                model.Komissar = 1;
                model.Mafia = 2;
                model.Maniac = 0;
                model.MinPlayers = 15;
                model.Private = 0;
                model.PublicVote = 0;
                model.RatingForEnter = 0.0;
                model.Reanimator = 0;
                model.Sheriff = 0;
                model.Thief = 0;
            }
            else
            {
                model.ModeCreate = false;
                model.Advocat = gd.Advocat;
                model.GameDescription = gd.GameDescription;
                model.GameName = gd.GameName;
                model.Schedule = GameSchedule.FromGameString(gd.GameSchedule);
                model.Girl = gd.Girl;
                model.Komissar = gd.Komissar;
                model.Mafia = gd.Mafia;
                model.Maniac = gd.Maniac;
                model.MinPlayers = gd.Players;
                model.Private = gd.Private;
                model.PublicVote = gd.PublicVote;
                model.RatingForEnter = gd.RatingForEnter;
                model.Reanimator = gd.Reanimator;
                model.Sheriff = gd.Sheriff;
                model.Thief = gd.Thief;
            }
            ViewData.Model = model;
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [AuthorizedValidated]        
        public ActionResult EditGame(FormCollection coll)
        {
            if (!Utils.IsModeratorAndAbove() && !Utils.ImOwner(coll["city"])) return new RedirectResult("/Home/JoinGame");

            HeritageEntities ents = new HeritageEntities();

            CityModel model = new CityModel();
            model.ModeCreate = string.IsNullOrEmpty(coll["city"]);
            model.Advocat = int.Parse(coll["advocat"]);
            model.GameDescription = coll["description"];
            GameDescriptions partyDesc = ents.GameDescriptions.Where(r => r.GameName.Trim() == "party").FirstOrDefault();
            if (model.ModeCreate)
            {
                model.GameName = "party" + partyDesc.GameNumber;
                partyDesc.GameNumber = partyDesc.GameNumber + 1;
            }

            else model.GameName = coll["city"].Trim();

            model.Girl = int.Parse(coll["girl"]);
            model.Komissar = int.Parse(coll["komissar"]);
            model.Mafia = int.Parse(coll["mafia"]);
            model.Maniac = int.Parse(coll["maniac"]);
            int max = -1;
            double mmax = 0;
            model.MinPlayers = int.TryParse(coll["minplayers"], out max) ? max : 0;
            model.Private = int.Parse(coll["private"]);
            model.PublicVote = int.Parse(coll["publicvote"]);
            model.RatingForEnter = double.TryParse(coll["ratingforenter"], out mmax) ? mmax : 0;
            model.Reanimator = int.Parse(coll["reanimator"]);
            model.Sheriff = int.Parse(coll["sheriff"]);
            model.Thief = int.Parse(coll["thief"]);

            if (model.GameDescription.Length == 0)
            {
                ModelState.AddModelError("err", "Описание города не должно быть пустым");
            }
            if (model.MinPlayers < 2 || model.MinPlayers > 25)
            {
                ModelState.AddModelError("err", "Партия должна содержать от 2 до 25 игроков");
            }
            string sched = "";
            sched += (coll["gamestarttime"] + ",");
            int hrs = 0;
            int mins = 0;
            bool error = false;
            int full = 2880;
            if (!int.TryParse(coll["firstday"], out hrs))
            {
                try
                {
                    string[] all = coll["firstday"].Split(new[] { ":" }, StringSplitOptions.None);
                    hrs = int.Parse(all[0]);
                    mins = int.Parse(all[1]);
                }
                catch
                {
                    ViewData["FirstDayLength"] = coll["firstday"];
                    error = true;
                    ModelState.AddModelError("err", "Длительность нулевого дня должна быть в формате чч:мм или просто чч");
                }
            }
            if (!error)
            {
                if (mins < 0 || mins > 59)
                {
                    ViewData["FirstDayLength"] = coll["firstday"];
                    ModelState.AddModelError("err", "Количество минут должно быть от 0 до 59");
                }
                full = hrs * 60 + mins;
                if (full <= 0)
                {
                    ViewData["FirstDayLength"] = coll["firstday"];
                    ModelState.AddModelError("err", "Длительность нулевого дня должна быть больше нуля");
                }
                if (full > 4320)
                {
                    ViewData["FirstDayLength"] = coll["firstday"];
                    ModelState.AddModelError("err", "Длительность нулевого дня должна быть меньше или равна 72 часам");
                }
            }
            sched += (full + ",");
            if (coll["snapturn"] != null) sched += "true,";
            else sched += "false,";

            hrs = 0;
            mins = 0;
            error = false;
            full = 2880;
            if (!int.TryParse(coll["turnstep"], out hrs))
            {
                try
                {
                    string[] all = coll["turnstep"].Split(new[] { ":" }, StringSplitOptions.None);
                    hrs = int.Parse(all[0]);
                    mins = int.Parse(all[1]);
                }
                catch
                {
                    ViewData["TurnLength"] = coll["turnstep"];
                    error = true;
                    ModelState.AddModelError("err", "Длительность хода должна быть в формате чч:мм или просто чч");
                }
            }
            if (!error)
            {
                if (mins < 0 || mins > 59)
                {
                    ViewData["TurnLength"] = coll["turnstep"];
                    ModelState.AddModelError("err", "Количество минут должно быть от 0 до 59");
                }
                full = hrs * 60 + mins;
                if (full <= 0)
                {
                    ViewData["TurnLength"] = coll["turnstep"];
                    ModelState.AddModelError("err", "Длительность хода должна быть больше нуля");
                }
                if (full > 4320)
                {
                    ViewData["TurnLength"] = coll["turnstep"];
                    ModelState.AddModelError("err", "Длительность хода должна быть меньше или равна 72 часам");
                }
            }
            sched += (full + ",");

            int start = int.Parse(coll["startinterval"]);
            int end = int.Parse(coll["endinterval"]);
            if (start > end)
            {
                ModelState.AddModelError("err", "Время начала игрового интервала должно быть раньше времени его конца");
            }
            sched += (start + "," + end + ",");
            string ds = "";
            if (coll["ch_1"] != null) ds += "A";
            if (coll["ch_2"] != null) ds += "B";
            if (coll["ch_3"] != null) ds += "C";
            if (coll["ch_4"] != null) ds += "D";
            if (coll["ch_5"] != null) ds += "E";
            if (coll["ch_6"] != null) ds += "F";
            if (coll["ch_7"] != null) ds += "G";
            if (ds.Length == 0)
            {
                ModelState.AddModelError("err", "Должен быть выбран хотя бы один игровой день");                
            }
            sched = sched+ds+",";
            model.Schedule = GameSchedule.FromGameString(sched); if (!ModelState.IsValid)
            {
                ViewData.Model = model;
                return View();
            }
            else
            {
                if (model.ModeCreate)
                {
                    Games desc = Games.CreateGames(model.GameName, "party", DateTime.Now, 0, Constants.GAME_STATE_AVAILABLE, model.RatingForEnter, model.Schedule.ToGameString(), model.Mafia, model.Komissar, model.Reanimator, model.Advocat, model.Sheriff, model.Maniac, model.Girl, model.Thief, model.MinPlayers, model.Private, model.PublicVote, 0, true);
                    desc.GameDescription = model.GameDescription;
                    ents.Games.AddObject(desc);
                    ents.SaveChanges();
                }
                else
                {
                    Games desc = ents.Games.Where(r => r.GameName == model.GameName).FirstOrDefault();
                    desc.Advocat = model.Advocat;
                    desc.GameDescription = model.GameDescription;
                    desc.GameSchedule = model.Schedule.ToGameString();
                    desc.Girl = model.Girl;
                    desc.Komissar = model.Komissar;
                    desc.Mafia = model.Mafia;
                    desc.Maniac = model.Maniac;
                    desc.Players = model.MinPlayers;
                    desc.Private = model.Private;
                    desc.PublicVote = model.PublicVote;
                    desc.RatingForEnter = model.RatingForEnter;
                    desc.Reanimator = model.Reanimator;
                    desc.Sheriff = model.Sheriff;
                    desc.Thief = model.Thief;
                    ents.SaveChanges();
                }
                return new RedirectResult("/Home/JoinGame");
            }
        }


        [AuthorizedValidated]
        [GameMaster]
        public ActionResult RemoveCity(string id)
        {
            HeritageEntities ents = new HeritageEntities();
            GameDescriptions descr = ents.GameDescriptions.Where(r => r.GameName == id).FirstOrDefault();
            if (descr != null) ents.GameDescriptions.DeleteObject(descr);
            ents.SaveChanges();
            return new RedirectResult("/GameMaster/Cities");
        }
        [AuthorizedValidated]
        [Moderator]
        public ActionResult DeleteGame(string id)
        {
            HeritageEntities ents = new HeritageEntities();
            Games g = ents.Games.Where(r => r.GameName == id).FirstOrDefault();
            if (g != null)
            {
                foreach (GameUserData u in ents.GameUserData.Where(r => r.GameName == id))
                {
                    Users user = ents.Users.Where(t => t.ID == u.UserID).FirstOrDefault();
                    if (user != null)
                    {
                        Utils.SendGameDeleteNotification(user.Email, id, user.Username);
                    }
                    ents.GameUserData.DeleteObject(u);
                }
                ents.Games.DeleteObject(g);
                LogService.Info(Utils.GetPrincipalName(), Constants.COMPONENT_GAMEMASTER, string.Format("Game {0} deleted", id));
                ents.SaveChanges();
            }
            return new RedirectResult("/Home/JoinGame");
        }

        [AuthorizedValidated]
        [ModeratorOrOwner]
        public ActionResult StartGame(string id)
        {
            Utils.StartOrContinueGame(id);
            return new RedirectResult(Request.UrlReferrer.AbsoluteUri);
        }

        [AuthorizedValidated]
        [ModeratorOrOwner]
        public ActionResult StopGame(string id)
        {
            Utils.StopGame(id);
            return new RedirectResult("/Home/ActiveGames");
        }

        [AuthorizedValidated]
        [ModeratorOrOwner]
        public ActionResult Restart(string id)
        {
            Utils.RestartGame(id);
            return new RedirectResult("/Home/ActiveGames");
        }

        [AuthorizedValidated]
        [ModeratorOrOwner]
        public ActionResult GameTurn(string id)
        {
            Utils.Turn(id);
            return new RedirectResult("/Home/ActiveGames");
        }
    }
}
